{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: combining MOD file ion channels with rxd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-rxd-and-mod\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NEURON's reaction-diffusion infrastructure can be used to readily allow intracellular concentrations to respond to currents generated in MOD files, as long as:\n", "\n", "- `nrn_region='i'` is specified for the `rxd.Region` (so that it knows it corresponds to the electrophysiology region of the inside of the cell), AND\n", "the name and charge of the ion/etc are given in the `rxd.Species` declaration.\n", "Satisfying the above two rules also allows MOD files to see intracellular concentrations.\n", "\n", "- 3D extracellular concentrations also interoperate with electrophysiology automatically as long as name and charge are specified.\n", "\n", "As a simple example, we consider a model with just a single point soma, of length and diameter 10 microns, with Hodgkin-Huxley kinetics (which uses the built in mod file `hh.mod`), and dynamic sodium (declared using rxd but without any additional kinetics)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:10:59.962802Z", "iopub.status.busy": "2025-09-09T10:10:59.962537Z", "iopub.status.idle": "2025-09-09T10:11:00.370853Z", "shell.execute_reply": "2025-09-09T10:11:00.370245Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import n, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "n.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.436889Z", "iopub.status.busy": "2025-09-09T10:11:00.436294Z", "iopub.status.idle": "2025-09-09T10:11:00.501714Z", "shell.execute_reply": "2025-09-09T10:11:00.501103Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.504454Z", "iopub.status.busy": "2025-09-09T10:11:00.504168Z", "iopub.status.idle": "2025-09-09T10:11:00.547787Z", "shell.execute_reply": "2025-09-09T10:11:00.547164Z" } }, "outputs": [], "source": [ "## define morphology\n", "soma = n.Section(name=\"soma\")\n", "soma.L = soma.diam = 10 * um\n", "\n", "## add ion channels (n.hh is built in, so always available)\n", "n.hh.insert(soma)\n", "\n", "## define cytosol. MUST specify nrn_region for concentrations to update\n", "cyt = rxd.Region([soma], name=\"cyt\", nrn_region=\"i\")\n", "\n", "## define sodium. MUST specify name and charge for concentrations to update\n", "na = rxd.Species(cyt, name=\"na\", charge=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we could have written `n.hh.insert(soma.wholetree())` to put Hodgkin-Huxley channels everywhere in the cell that the soma is part of, but since there is only one section, this is not required." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also add an excitatory synapse to receive events (these will trigger the cell to spike)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.550806Z", "iopub.status.busy": "2025-09-09T10:11:00.550540Z", "iopub.status.idle": "2025-09-09T10:11:00.555604Z", "shell.execute_reply": "2025-09-09T10:11:00.554935Z" } }, "outputs": [], "source": [ "syn = n.ExpSyn(soma(0.5))\n", "syn.tau = 1 * ms\n", "syn.e = 0 * mV" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add a stimulus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The spike events themselves (two events, 15 ms apart starting at n.t=10*ms):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.559587Z", "iopub.status.busy": "2025-09-09T10:11:00.558537Z", "iopub.status.idle": "2025-09-09T10:11:00.563457Z", "shell.execute_reply": "2025-09-09T10:11:00.562816Z" } }, "outputs": [], "source": [ "stim = n.NetStim()\n", "stim.interval = 15 * ms\n", "stim.number = 2\n", "stim.start = 10 * ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Send those events to our synapse:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.567302Z", "iopub.status.busy": "2025-09-09T10:11:00.566331Z", "iopub.status.idle": "2025-09-09T10:11:00.571012Z", "shell.execute_reply": "2025-09-09T10:11:00.570341Z" } }, "outputs": [], "source": [ "nc = n.NetCon(stim, syn)\n", "nc.weight[0] = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup recording variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.574035Z", "iopub.status.busy": "2025-09-09T10:11:00.573415Z", "iopub.status.idle": "2025-09-09T10:11:00.579117Z", "shell.execute_reply": "2025-09-09T10:11:00.578433Z" } }, "outputs": [], "source": [ "t = n.Vector().record(n._ref_t)\n", "v = n.Vector().record(soma(0.5)._ref_v)\n", "na_vec = n.Vector().record(soma(0.5)._ref_nai)\n", "ina = n.Vector().record(soma(0.5)._ref_ina)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize and run the simulation" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.581806Z", "iopub.status.busy": "2025-09-09T10:11:00.581546Z", "iopub.status.idle": "2025-09-09T10:11:00.605514Z", "shell.execute_reply": "2025-09-09T10:11:00.604906Z" } }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n.finitialize(-65 * mV)\n", "n.continuerun(50 * ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2025-09-09T10:11:00.608524Z", "iopub.status.busy": "2025-09-09T10:11:00.608278Z", "iopub.status.idle": "2025-09-09T10:11:00.945512Z", "shell.execute_reply": "2025-09-09T10:11:00.943469Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "